package master.userInterface;

import gates.*;

import java.awt.*;
import java.awt.event.*;
import java.util.List;
import java.util.*;
import javax.swing.*;
import javax.swing.border.Border;

import master.event.GateGenerationEvent;
import master.event.GateGenerationEventInitiator;
import master.event.GateGenerationListener;
import master.quantumComputerIO.gate.GateException;
import master.quantumComputerIO.gate.QuantumGateFactory;

public class GateIOPanel extends JPanel implements ActionListener, GateGenerationEventInitiator{
	private final QuantumGateFactory g;
	private final JLabel name;
	private final JButton createInstance;
	private final JLabel [] labels;
	private final JTextField [] fields;
	
	List<GateGenerationListener> listeners = new ArrayList<GateGenerationListener>();
	public void addGateGenerationListener(GateGenerationListener gglListener){
		if(gglListener!=null)listeners.add(gglListener);
	}
	public void generateGate(QuantumGate gate, Object [] constructorArguments){
		for(GateGenerationListener gglListener : listeners)
			gglListener.gateGenerated(new GateGenerationEvent(gate,constructorArguments));
	}
	
	public String getGateClassName(){
		return g.getGateName();
	}
	
	public static GateIOPanel [] panelsForGates(QuantumGateFactory [] g){
		GateIOPanel [] panArray = new GateIOPanel[g.length];
		for(int i = 0 ; i < g.length ; i++)
			panArray[i] = new GateIOPanel(g[i]);
		return panArray;
	}
	
	public GateIOPanel(QuantumGateFactory g){
		this.g = g;
		/**
		 * Set the title of this panel as the class name of the gate to be created
		 */
		if(g.getGateName().indexOf('.') != -1)
			this.name = new JLabel(g.getGateName().substring( g.getGateName().indexOf('.')+1 ));
		else
			this.name = new JLabel(g.getGateName());
		
		/**
		 * Create instance is the command button to create a new gate
		 */
		this.createInstance = new JButton("Create new " + name.getText());
		createInstance.addActionListener(this);
		
		this.labels = new JLabel[g.getGateArgumentTypes().length];
		this.fields = new JTextField[g.getGateArgumentTypes().length];
		
		for(int i = 0 ; i < g.getGateArgumentTypes().length;i++){
			labels[i] = new JLabel(
					g.getGateArgumentTypes()[i].toString() +
					"(" + ((i<g.getGateArgumentAnnotations().length)?g.getGateArgumentAnnotations()[i]:"") +
					 ")"
					);
		}
		for(int i = 0 ; i < g.getGateArgumentTypes().length;i++){
			fields[i] = new JTextField();
			fields[i].setColumns(10);
		}
		
		/**
		 * Add the components to the panel in a readable manner
		 */
		this.setLayout(new GridBagLayout());
		GridBagConstraints c = new GridBagConstraints();
		c.fill = GridBagConstraints.BOTH;
		c.weightx = 0.1;
		add(name,c);
		
		//add the labels
		c.gridy = 1;
		for(int i = 0 ; i < labels.length ; i++){
			c.gridx = i;
			add(labels[i],c);
		}
		c.gridy = 2;
		for(int i = 0 ; i < fields.length ; i++){
			c.gridx = i;
			add(fields[i],c);
		}
		
		c.weightx = 1;
		c.gridy = 0;
		c.gridx = fields.length-1;
		add(createInstance,c);
	}
	
	public void actionPerformed(ActionEvent e) {
		//attempt to create a new instance of the gate
		Object [] constructorArguments = new Object[fields.length];
		//attempt to parse the fields
		try{
		for(int i = 0 ; i < constructorArguments.length ; i++){
			Class type =g.getGateArgumentTypes()[i];
			if(type == int.class){
				constructorArguments[i] =(int) Integer.parseInt(fields[i].getText());
			}else if(type == float.class){
				constructorArguments[i] =(float) Double.parseDouble(fields[i].getText());
			}else if(type == double.class){
				constructorArguments[i] = (double)Double.parseDouble(fields[i].getText());
			}else if(type == boolean.class){
				constructorArguments[i] = (boolean)Boolean.parseBoolean(fields[i].getText());
			}else if(type == String.class){
				constructorArguments[i] = fields[i].getText();
			}
		}
		
		try {
			try{
				QuantumGate instanceOfGate =  g.getGate(constructorArguments);
				generateGate(instanceOfGate,constructorArguments);
			}catch(IllegalArgumentException ilE){
				JOptionPane.showMessageDialog(null, "Unable to create instance of gate: constructor error was thrown: "+ilE.getMessage());
			}
			//at this point, if the gate was successfully instansiated, send it
			//to the gate listeners
		} catch (GateException e1) {
			JOptionPane.showMessageDialog(null, "Unable to create gate");
		}
		
		}catch(NumberFormatException e2){
			JOptionPane.showMessageDialog(null, "Unable to create gate");
		}
		
	}
}
